﻿using HARTCalibrationTool.Commands.TwoDimensionalCMDGroup;
using HARTCalibrationTool.SerialPortManager;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace HARTCalibrationTool.Commands.BatchCalibrationBoard
{
    public static class BatchCaliBoardObserversInfo
    {
        public static Dictionary<string, string> info = new Dictionary<string, string>()
        {
            { "HART Channel Switch", "HART Chl Change"},
            { "Meter Channel Switch", "Meter Chl Change"},
        };
    }
    
    public abstract class BatchCaliBoardCMDsBase : CommandsBase
    {
        private BatchCaliBoardCMDStruct stBatchCaliBoardCMD;
        private static CMDsChannelID _currentOpenChl;

        public enum BatchCaliBoardCMDID
        {
            eSwitchHARTChannel = 0x01,
            eSwitchMeterChannel = 0x02,
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        private struct BatchCaliBoardCMDStruct
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public byte header1;
            public byte header2;
            public byte CMDCode;
            public byte size;
            public byte[] data;
            public byte checkSum;
            public byte tail1;
            public byte tail2;
        }

        public byte CMDCode
        {
            set { stBatchCaliBoardCMD.CMDCode = value; }
            get { return stBatchCaliBoardCMD.CMDCode; }
        }

        public byte Size
        {
            set { stBatchCaliBoardCMD.size = value; }
            get { return stBatchCaliBoardCMD.size; }
        }

        public byte[] Data
        {
            set { stBatchCaliBoardCMD.data = value; }
            get { return stBatchCaliBoardCMD.data; }
        }

        public CMDsChannelID CurrentOpenChannel
        {
            set { _currentOpenChl = value; }
            get { return _currentOpenChl; }
        }

        public BatchCaliBoardCMDsBase(SerialPortsBase serialPortManager, string commandName) : base(serialPortManager, commandName)
        {
            stBatchCaliBoardCMD = new BatchCaliBoardCMDStruct()
            {
                header1 = 0xAA,
                header2 = 0x55,
                CMDCode = 0,
                size = 0,
                data = null,
                checkSum = 0,
                tail1 = 0x0D,
                tail2 = 0x0A,
            };
        }

        protected byte[] GetCMDBytes()
        {
            byte checkSum = 0;
            List<byte> data = new List<byte>();

            data.Add(stBatchCaliBoardCMD.header1);
            data.Add(stBatchCaliBoardCMD.header2);
            data.Add(stBatchCaliBoardCMD.CMDCode);
            data.Add(stBatchCaliBoardCMD.size);

            if ((Size != 0) && (Data != null))
            {
                for (byte i = 0; i < Size; i++)
                {
                    data.Add(Data[i]);
                }
            }
            else
            {
                return null;
            }

            foreach (byte value in data)
            { 
                checkSum += value;
            }

            data.Add(checkSum);
            data.Add(stBatchCaliBoardCMD.tail1);
            data.Add(stBatchCaliBoardCMD.tail2);

            return data.ToArray();
        }

        public override async Task ExecuteCMD()
        {
            await SendCMD();
        }

        public override async Task ParseResponse(byte[] data)
        {
            await Task.Run(() => { });
        }

        protected abstract Task SendCMD();

        public override VerifyDataFrameStatus VerifyDataFrameIntegrity(byte[] data)
        {
            byte tail = 0;

            // header(2 bytes) + CMDCode(1 byte) + size(1 byte) + data(n bytes) + checksum(1 byte) + tail(2 bytes)
            tail = (byte)(3 + data[3] + 2);
            if (data.Length < (tail + 2))
            {
                return VerifyDataFrameStatus.eWaiting;
            }

            if ((data[0] != 0xAA) || (data[1] != 0x55) || (data[tail] != 0x0D) || (data[tail + 1] != 0x0A))
            {
                return VerifyDataFrameStatus.eError;
            }

            return VerifyDataFrameStatus.eSuccess;
        }
    }
}
